package symbols;

/**
 * An entry for a function, a sub or a predicate in the symbol table
 * 
 * @author marc
 *
 */
public class SCallable extends Symbol {
	private ParameterList params = null;
	private /*SimpleNode*/ Object body = null;
	private ISymbolTable st = null;
	private int returnType = -1;
	
	public void setReturnType(int type) {
		returnType = type;
	}
	
	public int getReturnType() {
		return returnType;
	}
	
	public SCallable(int type, String name, ParameterList params, Object body, ISymbolTable st ) {
		super(type, name);
		this.params = params;
		this.body = body;
		this.st = st;
	}

	public String toString() {
		return "Identifier of type " + Type.names[type] + " " + internalsDescription();
	}
	
	public String internalsDescription() {
		StringBuffer sb = new StringBuffer();
		sb.append("	|   parameters: "  + params);
		sb.append("	|   body: " + body.hashCode());
		sb.append("	|   symbol table: ");
		sb.append(st.hashCode());
		return sb.toString();
	}

	/**
	 * The callable must keep track of its code for the moment
	 * it will be asked to evaluate it.
	 * 
	 * @param ASTBODY body
	 */
	public void setBody(Object body) {
		this.body = body;
	}
	
	/**
	 * Return the ASTbody tree root
	 * @return
	 */
	public Object getBody() {
		return body;
	}
	
	/**
	 * Parameters belong to the "callable" scope.
	 * This method adds them to the symbol table for this scope.
	 * @param paramSymbols
	 * 
	 * @deprecated constructor (one-time) should be used instead ; and symbolTable should contain everything already
	 
	public void setParams(ISymbolTable paramSymbols) {
		st.addAllToScope(paramSymbols);
	}
	*/
	
	/**
	 * Let the function remember its symbol table 
	 * and its scope
	 * @param s
	 * @deprecated constructor (one-time) should be used instead ; and symbolTable should contain everything already
	 * 
	public void setSymbolTable(ISymbolTable s) {
		st = s;
	}
	*/
	
	/**
	 * Predicate telling if a symbol is defined or redefined
	 * in this scope
	 * @param sym
	 * @return true if <code>sym</code> is defined or redefined in this scope
	 */
	public boolean defines(String sym) {
		return st.contains(sym);
	}
	
	/**
	 * 
	 * @param sym
	 * @return returns the identifier by name if it is defined in this scope
	 * @throws Exception when the identifier is not defined in this scope
	 */
	public SLeftValue getIdentifier(String sym) throws Exception {
		if(!defines(sym))
			throw new Exception(name + ": Identifier " + sym + " is not defined in this scope");	// meant to be caught by direct caller
		return (SLeftValue)st.get(sym);
	}
	
	/**
	 * 
	 * @return the list of parameter names (keys in the symbol table)
	 */
	public ParameterList getParameterList() {
		return params;
	}

	/**
	 * 
	 * @return its symbol table 
	 */
	public ISymbolTable getSymbolTable() {
		return st;
	}

	public ISymbolTable cloneSymbolTable() {
		return (ISymbolTable)st.clone();
	}
}
